﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Globalization;

namespace Enterprise.Utilities
{
    public static class DateHelper
    {
        // Methods
        public static DateTime ConvertDateFromUtc(DateTime dateValue, TimeZoneInfo timeZone)
        {
            if (timeZone == null)
            {
                throw new ArgumentNullException("timeZone");
            }
            if (!IsLocal(dateValue))
            {
                return DateTime.SpecifyKind(TimeZoneInfo.ConvertTimeFromUtc(dateValue, timeZone), DateTimeKind.Local);
            }
            return dateValue;
        }

        public static void ConvertDatesFromUtc(object entity, bool convertDescendents)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            TimeZoneInfo timeZoneForCurrentUser = GetTimeZoneForCurrentUser();
            foreach (PropertyInfo info2 in GetAllDates(entity))
            {
                DateTime propertyValue = ConvertDateFromUtc(Convert.ToDateTime(ReflectionHelper.GetPropertyValue(entity, info2.Name)), timeZoneForCurrentUser);
                ReflectionHelper.SetPropertyValue(entity, info2.Name, propertyValue);
            }
            foreach (PropertyInfo info3 in GetAllNullableDates(entity))
            {
                DateTime? dateValue = ReflectionHelper.ConvertType(ReflectionHelper.GetPropertyValue(entity, info3.Name), typeof(DateTime?)) as DateTime?;
                if (dateValue.HasValue)
                {
                    DateTime? nullable2 = ConvertNullableDateFromUtc(dateValue, timeZoneForCurrentUser);
                    ReflectionHelper.SetPropertyValue(entity, info3.Name, nullable2);
                }
            }
            if (convertDescendents)
            {
                foreach (object obj2 in ReflectionHelper.Flatten(entity))
                {
                    ConvertDatesFromUtc(obj2, false);
                }
            }
        }

        public static void ConvertDatesToUtc(object entity, bool convertDescendents)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            TimeZoneInfo timeZoneForCurrentUser = GetTimeZoneForCurrentUser();
            foreach (PropertyInfo info2 in GetAllDates(entity))
            {
                DateTime propertyValue = (DateTime)ReflectionHelper.GetPropertyValue(entity, info2.Name);
                if (!IsUtc(propertyValue))
                {
                    ReflectionHelper.SetPropertyValue(entity, info2.Name, ConvertDateToUtc(propertyValue, timeZoneForCurrentUser));
                }
            }
            foreach (PropertyInfo info3 in GetAllNullableDates(entity))
            {
                DateTime? dateValue = ReflectionHelper.GetPropertyValue(entity, info3.Name) as DateTime?;
                if (!IsUtc(dateValue.Value))
                {
                    ReflectionHelper.SetPropertyValue(entity, info3.Name, ConvertNullableDateToUtc(dateValue, timeZoneForCurrentUser));
                }
            }
            if (convertDescendents)
            {
                foreach (object obj2 in ReflectionHelper.Flatten(entity))
                {
                    ConvertDatesToUtc(obj2, false);
                }
            }
        }

        public static DateTime ConvertDateToUtc(DateTime dateValue, TimeZoneInfo timeZone)
        {
            if (timeZone == null)
            {
                throw new ArgumentNullException("timeZone");
            }
            if (!IsUtc(dateValue))
            {
                return TimeZoneInfo.ConvertTimeToUtc(dateValue, timeZone);
            }
            return dateValue;
        }

        public static DateTime? ConvertNullableDateFromUtc(DateTime? dateValue, TimeZoneInfo timeZone)
        {
            if (timeZone == null)
            {
                throw new ArgumentNullException("timeZone");
            }
            if (!dateValue.HasValue)
            {
                throw new ArgumentNullException("dateValue");
            }
            DateTime time = dateValue.Value;
            if (!IsLocal(time))
            {
                time = DateTime.SpecifyKind(TimeZoneInfo.ConvertTimeFromUtc(time, timeZone), DateTimeKind.Local);
            }
            return new DateTime?(time);
        }

        public static DateTime? ConvertNullableDateToUtc(DateTime? dateValue, TimeZoneInfo timeZone)
        {
            if (timeZone == null)
            {
                throw new ArgumentNullException("timeZone");
            }
            if (!dateValue.HasValue)
            {
                throw new ArgumentNullException("dateValue");
            }
            DateTime time = dateValue.Value;
            if (!IsUtc(time))
            {
                time = TimeZoneInfo.ConvertTimeToUtc(time, timeZone);
            }
            return new DateTime?(time);
        }

        private static IEnumerable<PropertyInfo> GetAllDates(object entity)
        {
            Type type = entity.GetType();
            BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance;
            return type.GetProperties(bindingAttr).Where<PropertyInfo>(delegate(PropertyInfo p)
            {
                return (p.PropertyType == typeof(DateTime));
            });
        }

        private static IEnumerable<PropertyInfo> GetAllNullableDates(object entity)
        {
            Type type = entity.GetType();
            BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance;
            return type.GetProperties(bindingAttr).Where<PropertyInfo>(delegate(PropertyInfo p)
            {
                return (p.PropertyType == typeof(DateTime?));
            });
        }

        public static TimeZoneInfo GetTimeZoneForCurrentUser()
        {
            return TimeZoneInfo.Local;
        }

        public static bool IsDate(string target)
        {
            DateTime time;
            return DateTime.TryParse(target, CultureInfo.CurrentCulture, DateTimeStyles.None, out time);
        }

        public static bool IsDate(string target, out DateTime output)
        {
            return DateTime.TryParse(target, CultureInfo.CurrentCulture, DateTimeStyles.None, out output);
        }

        public static bool IsLocal(DateTime dateValue)
        {
            return (dateValue.Kind == DateTimeKind.Local);
        }

        public static bool IsUtc(DateTime dateValue)
        {
            return (dateValue.Kind == DateTimeKind.Utc);
        }

    }
}
